

#include <iostream>
#include <vector>
#include <iomanip>

using namespace std;

class Packing
{
public:
    virtual std::string packet() = 0;
};

class Wrapper : public Packing
{
public:
    virtual string packet() override
    {
        return "wrapper";
    }
};

class Bottle : public Packing
{
public:
    virtual string packet() override
    {
        return "bottle";
    }
};

class Item
{
public:
    virtual std::string getName() = 0;
    virtual Packing *getPacking() = 0;
    virtual float getPrice() = 0;
    virtual void setPrice(float price) = 0;
};

class Burger : public Item
{
public:
    virtual std::string getName() override
    {
        return "Burger";
    }

    virtual Packing *getPacking() override
    {
        return new Wrapper();
    }

    virtual float getPrice() override
    {
        return price;
    }

    virtual void setPrice(float price) override
    {
        this->price = price;
    }

private:
    float price;
};

class VegBurger : public Burger
{
public:
    VegBurger()
    {
        setPrice(10.5);
    }

    VegBurger(float price)
    {
        setPrice(price);
    }

    string getName()
    {
        return "VegBurger";
    }
};

class ChickenBurger : public Burger
{
public:
    ChickenBurger()
    {
        setPrice(30.5);
    }

    ChickenBurger(float price)
    {
        setPrice(price);
    }

    string getName()
    {
        return "ChickenBurger";
    }
};

class ClodDrink : public Item
{

public:
    virtual std::string getName() override
    {
        return "ClodDrink";
    }

    virtual Packing *getPacking() override
    {
        return new Bottle();
    }

    virtual float getPrice() override
    {
        return price;
    }

    virtual void setPrice(float price) override
    {
        this->price = price;
    }

private:
    float price;
};

class Pepsi : public ClodDrink
{
public:
    Pepsi()
    {
        setPrice(5.5);
    }

    Pepsi(float price)
    {
        setPrice(price);
    }

    string getName()
    {
        return "Pepsi";
    }
};

class Coke : public ClodDrink
{
public:
    Coke()
    {
        setPrice(4.5);
    }

    Coke(float price)
    {
        setPrice(price);
    }

    string getName()
    {
        return "Coke";
    }
};

class Meal
{
public:
    Meal() : totlePrice(0) {}
    ~Meal()
    {
        items.clear();
    }

    void addItem(Item *item)
    {
        items.push_back(item);
    }

    void showItem()
    {
        cout << "the meal include:" << endl;
        for (int i = 0; i < items.size(); i++)
        {
            cout << "item:" << items[i]->getName() << ", " << items[i]->getPacking()->packet() << ", "
                 << fixed << setprecision(2) << items[i]->getPrice() << endl;
        }
    }

    float getCost()
    {
        for (int i = 0; i < items.size(); i++)
        {
            totlePrice += items[i]->getPrice();
        }

        return totlePrice;
    }

private:
    vector<Item *> items;
    float totlePrice;
};

class MealBuilder
{
public:
    MealBuilder()
    {
        meal = new Meal();
    }

    ~MealBuilder()
    {
        delete meal;
        meal = NULL;
    }

    void selfSelectMeal(Item *item)
    {
        meal->addItem(item);
    }

    void prepareMeatMeal()
    {
        ClodDrink *clodDrink = new Coke();
        Burger *burger = new ChickenBurger();
        meal->addItem(clodDrink);
        meal->addItem(burger);
    }

    void prepareVegMeal()
    {
        ClodDrink *clodDrink = new Pepsi();
        Burger *burger = new VegBurger();
        meal->addItem(clodDrink);
        meal->addItem(burger);
    }

    void showMealDetail()
    {
        meal->showItem();
        cout << "total price:" << meal->getCost() << endl;
    }

private:
    Meal *meal;
};

int main(int argc, char *argv[])
{
    MealBuilder *mealBuilder1 = new MealBuilder();
    mealBuilder1->prepareMeatMeal();
    mealBuilder1->showMealDetail();

    MealBuilder *mealBuilder2 = new MealBuilder();
    mealBuilder2->prepareVegMeal();
    mealBuilder2->showMealDetail();

    MealBuilder *mealBuilder3 = new MealBuilder();
    Item *chickenBurger = new ChickenBurger();
    Item *vegBurger = new VegBurger();
    Item *pepsi = new Pepsi();
    mealBuilder3->selfSelectMeal(chickenBurger);
    mealBuilder3->selfSelectMeal(vegBurger);
    mealBuilder3->selfSelectMeal(pepsi);
    mealBuilder3->showMealDetail();

    delete mealBuilder1;
    delete mealBuilder2;
    delete mealBuilder3;
    return 0;
}